import { _decorator, Component, EventTouch, Vec2, Vec3, Camera, geometry, PhysicsSystem, input, Input } from 'cc';
const { ccclass, property } = _decorator;
import { BilliardGame } from './BilliardGame';
import { EventManager } from '../core/EventManager';
import { Game } from '../core/Game';
import { TableAtrribute } from '../core/TableAttribute';
import { distanceLength, distanceLengthV2 } from '../core/CommUtil';
import { BallAttribute } from '../core/BallAttribute';

@ccclass('TouchController')
export class TouchController extends Component {
  // Specify the camera rendering the target node.
  @property(Camera)
  readonly cameraCom!: Camera;
  public static DeskUIPositionX = 590;
  private _ray: geometry.Ray = new geometry.Ray();
  private tourchScreenStartPos: Vec2 = new Vec2();
  private tourchScreenMovePos: Vec2 = new Vec2(0, 0);
  private tourchScreenMoveEndPos: Vec2 = new Vec2(-100, -100);
  private startMoveDirection = false;
  // 自由球
  private isFreeMoveBall = false;
  onLoad() {
  }
  onEnable () {
    input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
    input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
    input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
  }

  update(deltaTime: number) {
    
  }
  public onTouchStart(e: EventTouch) {
    this.startMoveDirection = false;
    if (!Game.Instance().isSelftHitBall()) return;
    const loc: Vec2 = e.getUILocation();
    this.tourchScreenStartPos.set(loc.x, loc.y);
    this.tourchScreenMovePos.set(loc);
    this.isFreeMoveBall = false;
    if (BilliardGame.Instance().isFreeKickBall() && BilliardGame.Instance().actionStage.isInitStage()) {
      // 触摸白球，操作步灵活，可以在白球mask上的区域都可以当做触摸白球进行移动
      const hitPos = this.isTouchedDesk(e);
      if (hitPos) {
        if (this.isAroundWhiteBall(hitPos)) {
          this.isFreeMoveBall = true;
          EventManager.Instance().Emit('HideQiuGanAimCommponent', {});
          return;
        }
      }
    }
  }
  public onTouchMove(e: EventTouch) {
    if (!Game.Instance().isSelftHitBall()) return;
    // 自由球时：移动白球
    if (this.isFreeMoveBall) {
      const pos = this.touchedDeskTop(e);
      if (BilliardGame.Instance().isFreeKickBall() && BilliardGame.Instance().actionStage.isInitStage()) {
        EventManager.Instance().Emit("ResetMainBallPosition", pos);
      }
      return;
    }
    const loc: Vec2 = e.getUILocation();
    if (BilliardGame.Instance().actionStage.isInitStage()) {
      const delta = (loc.y - this.tourchScreenMovePos.y);
      const fact = BilliardGame.Instance().calculateDirectionFactor();
      EventManager.Instance().Emit("QiuGanDirectionChanged", 1.25 * delta * fact);
      this.startMoveDirection = true;
      this.tourchScreenMovePos.set(loc);
      this.tourchScreenMoveEndPos.set(loc);
    }
  }
  public onTouchEnd(e: EventTouch) {
    EventManager.Instance().Emit('TouchClickPoint', e);
    if (!Game.Instance().isSelftHitBall()) return;
    if (BilliardGame.Instance().actionStage.hasHitMainBall()) {
      return;
    }
    // 自由球则结束
    if (this.isFreeMoveBall) {
      EventManager.Instance().Emit("HitBallHasChoosed", BilliardGame.Instance().getWhiteBallNearPosition());
      EventManager.Instance().Emit('ShowQiuGanAimCommponent', {});
      return;
    }
    const loc: Vec2 = e.getUILocation();
    const hitBall = this.isTouchedBall(e);
    if (hitBall) {
      EventManager.Instance().Emit("HitBallHasChoosed", hitBall.worldPosition);
      return hitBall;
    }
    // 如果是点击，瞄准台面上的任意位置
    if (!this.startMoveDirection && Math.abs(loc.x - this.tourchScreenStartPos.x) <= 100 && Math.abs(loc.y - this.tourchScreenStartPos.y) <= 100){
      const dist = distanceLengthV2(loc, this.tourchScreenMoveEndPos);
      if (dist > 50) {
        const hitPos = this.isTouchedDesk(e);
        if (hitPos) {
          hitPos.y = TableAtrribute.DeskTopAxisY;
          EventManager.Instance().Emit("HitBallHasChoosed", hitPos);
          return hitPos;
        }
      }
    }
  }
  private isTouchedBall(e: EventTouch) {
    const balls = BilliardGame.Instance().getActiveBalls();
    const touch = e.touch!;
    this.cameraCom.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
    if (PhysicsSystem.instance.raycast(this._ray)) {
      const raycastResults = PhysicsSystem.instance.raycastResults;
      for (let i = 0; i < raycastResults.length; i++) {
        const item = raycastResults[i];
        for (const ball of balls) {
          if (item.collider.node.name === ball.name) {
            console.log('raycast hit the target node !', ball);
            return ball;
          }
        } 
      }
    }
    const deskPoint = this.isTouchedDesk(e);
    if (!deskPoint) return null;
    for (const ball of balls) {
      const dist = distanceLength(ball.worldPosition, deskPoint);
      if (dist <= 2 * BallAttribute.radius) {
        console.log('extend tourch ball ', ball);
        return ball;
      }
    }
    return null;
  }

  private isTouchedDesk(e: EventTouch) {
    const names = BilliardGame.Instance().getDeskComponentNames();
    const touch = e.touch!;
    this.cameraCom.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
    if (PhysicsSystem.instance.raycast(this._ray)) {
      const raycastResults = PhysicsSystem.instance.raycastResults;
      for (let i = 0; i < raycastResults.length; i++) {
        const item = raycastResults[i];
        if (names.indexOf(item.collider.node.name) >= 0 ) {
          return item.hitPoint;
        }
      }
    }
    return null;
  }

  private touchedDeskTop(e: EventTouch) {
    const touch = e.touch!;
    this.cameraCom.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
    if (Math.abs(this._ray.d.y) <= 0.01) {
      return new Vec3(this._ray.o);
    }
    const lambda = (TableAtrribute.DeskTopAxisY - this._ray.o.y) / this._ray.d.y;
    return new Vec3(this._ray.o.x + lambda * this._ray.d.x, TableAtrribute.DeskTopAxisY , this._ray.o.z + lambda * this._ray.d.z);
  }

  private isAroundWhiteBall(pos: Vec3) {
    const mb = BilliardGame.Instance().getMainWhiteBall();
    const dist = (mb.worldPosition.x - pos.x) * (mb.worldPosition.x - pos.x) +
      (mb.worldPosition.z - pos.z) * (mb.worldPosition.z - pos.z);
    return dist < 4;
  }
}

